use crate::action::user::get_users;
use crate::data::message::Message;
use crate::fairing::user::UserDb;
use crate::guard::userauth::AdminUserData;
use crate::model::user::UserData;
use rocket::http::Status;
use rocket::request::Request;
use rocket::response::{self, Responder, Response};
use rocket::route::Route;
use rocket::serde::json::Json;
use rocket_db_pools::{
    sqlx::{self, Acquire},
    Connection,
};

enum GetUserStatus {
    Ok(Vec<UserData>),
    Failed(sqlx::Error),
}

impl<'r> Responder<'r, 'static> for GetUserStatus {
    fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
        match self {
            GetUserStatus::Ok(users) => Response::build_from(Json(users).respond_to(req)?)
                .status(Status::Ok)
                .ok(),
            GetUserStatus::Failed(err) => Response::build_from(
                Json(Message {
                    message: err.to_string(),
                })
                .respond_to(req)?,
            )
            .status(Status::InternalServerError)
            .ok(),
        }
    }
}

#[get("/")]
async fn list(mut db: Connection<UserDb>, _user: AdminUserData) -> GetUserStatus {
    let result = async {
        let mut tx = db.begin().await?;

        let users = get_users(&mut tx).await?;

        tx.commit().await?;
        Ok(GetUserStatus::Ok(users))
    }
    .await;
    match result {
        Ok(status) => status,
        Err(err) => GetUserStatus::Failed(err),
    }
}

pub fn route() -> Vec<Route> {
    routes![list]
}
